﻿#pragma once

#include "CoreMinimal.h"
#include "FInt128.h"

/**
 * 有符号定点数实现, 1bit代表正负符号位 31bit代表整数 32bit小数部分
 */
struct FFix32
{
private:
	int64 Value;

public:
	static constexpr int64 Fix32_One = 0x100000000;     /** 1的FFix32表示 */
	static constexpr int64 Fix32_HalfOne = 0x80000000;  /** 0.5的FFix32表示 */
	
protected:
	FORCEINLINE static int64 Fix32FromFloat(float A)
	{
		const float Temp = Fix32_One * A;
		return Temp;
	}

	FORCEINLINE static int64 Fix32FromDouble(double A)
	{
		const double Temp = Fix32_One * A;
		return Temp;
	}

	FORCEINLINE static int64 Fix32FromInt(int32 A)
	{
		const int64 Temp = Fix32_One * A;
		return Temp;
	}
	
	FORCEINLINE static float Fix32ToFloat(int64 A)
	{
		return static_cast<float>(A) / Fix32_One;
	}
	
	FORCEINLINE static double Fix32ToDouble(int64 A)
	{
		return static_cast<double>(A) / Fix32_One;
	}
	
	FORCEINLINE static int32 Fix32ToInt(int64 A)
	{
		return A >> 32;
	}

	FORCEINLINE static int64 Fix16Mul(int64 A, int64 B)
	{
		return static_cast<int64>((BigMath::FInt128(A) * BigMath::FInt128(B)) >> 32);
	}

	FORCEINLINE static int64 Fix16Div(int64 A, int64 B)
	{
		return static_cast<int64>((BigMath::FInt128(A) << 32) / BigMath::FInt128(B));
	}

public:
	FFix32() { Value = 0; }
	FFix32(const FFix32& InValue) { Value = InValue.Value; }
	FFix32(const int64 InValue)   { Value = InValue;   }
	FFix32(const float InValue)   { Value = Fix32FromFloat(InValue);   }
	FFix32(const double InValue)  { Value = Fix32FromDouble(InValue);  }
	FFix32(const int32 InValue)   { Value = Fix32FromInt(InValue);  }

	operator int64() const { return Value; }
	operator double()  const { return Fix32ToDouble(Value);   }
	operator float()   const { return Fix32ToFloat(Value); }
	operator int32() const { return Fix32ToInt(Value);   }

	FFix32& operator=(const FFix32& RHS) { Value = RHS.Value;             return *this; }
	FFix32& operator=(const int64 RHS)   { Value = RHS;                   return *this; }
	FFix32& operator=(const double RHS)  { Value = Fix32FromDouble(RHS);   return *this; }
	FFix32& operator=(const float RHS)   { Value = Fix32FromFloat(RHS); return *this; }
	FFix32& operator=(const int32 RHS)   { Value = Fix32FromInt(RHS);   return *this; }

	FFix32& operator+=(const FFix32& RHS)  { Value += RHS.Value;             return *this; }
	FFix32& operator+=(const int64 RHS)   { Value += RHS;                   return *this; }
	FFix32& operator+=(const double RHS)  { Value += Fix32FromDouble(RHS);   return *this; }
	FFix32& operator+=(const float RHS)   { Value += Fix32FromFloat(RHS); return *this; }
	FFix32& operator+=(const int32 RHS) { Value += Fix32FromInt(RHS);   return *this; }

	FFix32& operator-=(const FFix32& RHS)  { Value -= RHS.Value; return *this; }
	FFix32& operator-=(const int64 RHS)   { Value -= RHS; return *this; }
	FFix32& operator-=(const double RHS)  { Value -= Fix32FromDouble(RHS); return *this; }
	FFix32& operator-=(const float RHS)   { Value -= Fix32FromFloat(RHS); return *this; }
	FFix32& operator-=(const int32 RHS) { Value -= Fix32FromInt(RHS); return *this; }

	FFix32& operator*=(const FFix32& RHS)  { Value = Fix16Mul(Value, RHS.Value); return *this; }
	FFix32& operator*=(const int64 RHS)   { Value = Fix16Mul(Value, RHS); return *this; }
	FFix32& operator*=(const double RHS)  { Value = Fix16Mul(Value, Fix32FromDouble(RHS)); return *this; }
	FFix32& operator*=(const float RHS)   { Value = Fix16Mul(Value, Fix32FromFloat(RHS)); return *this; }
	FFix32& operator*=(const int32 RHS) { Value *= RHS; return *this; }

	FFix32& operator/=(const FFix32& RHS)  { Value = Fix16Div(Value, RHS.Value); return *this; }
	FFix32& operator/=(const int64 RHS)   { Value = Fix16Div(Value, RHS); return *this; }
	FFix32& operator/=(const double RHS)  { Value = Fix16Div(Value, Fix32FromDouble(RHS)); return *this; }
	FFix32& operator/=(const float RHS)   { Value = Fix16Div(Value, Fix32FromFloat(RHS)); return *this; }
	FFix32& operator/=(const int32 RHS) { Value /= RHS; return *this; }

	FFix32 operator+(const FFix32& Other) const { FFix32 Ret = *this; Ret += Other; return Ret; }
	FFix32 operator+(const int64 Other) const   { FFix32 Ret = *this; Ret += Other; return Ret; }
	FFix32 operator+(const double Other) const  { FFix32 Ret = *this; Ret += Other; return Ret; }
	FFix32 operator+(const float Other) const   { FFix32 Ret = *this; Ret += Other; return Ret; }
	FFix32 operator+(const int32 Other) const { FFix32 Ret = *this; Ret += Other; return Ret; }

	FFix32 operator-(const FFix32 &Other) const { FFix32 Ret = *this; Ret -= Other; return Ret; }
	FFix32 operator-(const int64 Other) const { FFix32 Ret = *this; Ret -= Other; return Ret; }
	FFix32 operator-(const double Other) const  { FFix32 Ret = *this; Ret -= Other; return Ret; }
	FFix32 operator-(const float Other) const   { FFix32 Ret = *this; Ret -= Other; return Ret; }
	FFix32 operator-(const int32 Other) const { FFix32 Ret = *this; Ret -= Other; return Ret; }
	
	FFix32 operator*(const FFix32 &Other) const { FFix32 Ret = *this; Ret *= Other; return Ret; }
	FFix32 operator*(const int64 Other) const { FFix32 Ret = *this; Ret *= Other; return Ret; }
	FFix32 operator*(const double Other) const  { FFix32 Ret = *this; Ret *= Other; return Ret; }
	FFix32 operator*(const float Other) const   { FFix32 Ret = *this; Ret *= Other; return Ret; }
	FFix32 operator*(const int32 Other) const { FFix32 Ret = *this; Ret *= Other; return Ret; }
	
	FFix32 operator/(const FFix32 &Other) const  { FFix32 Ret = *this; Ret /= Other; return Ret; }
	FFix32 operator/(const int64 Other) const { FFix32 Ret = *this; Ret /= Other; return Ret; }
	FFix32 operator/(const double Other) const  { FFix32 Ret = *this; Ret /= Other; return Ret; }
	FFix32 operator/(const float Other) const   { FFix32 Ret = *this; Ret /= Other; return Ret; }
	FFix32 operator/(const int32 Other) const { FFix32 Ret = *this; Ret /= Other; return Ret; }

	int32 operator==(const FFix32& Other)  const { return (Value == Other.Value);             }
	int32 operator==(const int64 Other) const { return (Value == Other);                   }
	int32 operator==(const double Other)  const { return (Value == Fix32FromDouble(Other));   }
	int32 operator==(const float Other)   const { return (Value == Fix32FromFloat(Other)); }
	int32 operator==(const int32 Other) const { return (Value == Fix32FromInt(Other));   }

	int32 operator!=(const FFix32& Other)  const { return (Value != Other.Value);             }
	int32 operator!=(const int64 Other) const { return (Value != Other);                   }
	int32 operator!=(const double Other)  const { return (Value != Fix32FromDouble(Other));   }
	int32 operator!=(const float Other)   const { return (Value != Fix32FromFloat(Other)); }
	int32 operator!=(const int32 Other) const { return (Value != Fix32FromInt(Other));   }

	int32 operator<=(const FFix32& Other)  const { return (Value <= Other.Value);             }
	int32 operator<=(const int64 Other) const { return (Value <= Other);                   }
	int32 operator<=(const double Other)  const { return (Value <= Fix32FromDouble(Other));   }
	int32 operator<=(const float Other)   const { return (Value <= Fix32FromFloat(Other)); }
	int32 operator<=(const int32 Other) const { return (Value <= Fix32FromInt(Other));   }

	int32 operator>=(const FFix32 &Other)  const { return (Value >= Other.Value);             }
	int32 operator>=(const int64 Other) const { return (Value >= Other);                   }
	int32 operator>=(const double Other)  const { return (Value >= Fix32FromDouble(Other));   }
	int32 operator>=(const float Other)   const { return (Value >= Fix32FromFloat(Other)); }
	int32 operator>=(const int32 Other) const { return (Value >= Fix32FromInt(Other));   }

	int32 operator< (const FFix32& Other)  const { return (Value <  Other.Value);             }
	int32 operator< (const int64 Other) const { return (Value <  Other);                   }
	int32 operator< (const double Other)  const { return (Value < Fix32FromDouble(Other));   }
	int32 operator< (const float Other)   const { return (Value < Fix32FromFloat(Other)); }
	int32 operator< (const int32 Other) const { return (Value < Fix32FromInt(Other));   }

	int32 operator> (const FFix32& Other)  const { return (Value > Other.Value);             }
	int32 operator> (const int64 Other) const { return (Value > Other);                   }
	int32 operator> (const double Other)  const { return (Value > Fix32FromDouble(Other));   }
	int32 operator> (const float Other)   const { return (Value > Fix32FromFloat(Other)); }
	int32 operator> (const int32 Other) const { return (Value > Fix32FromInt(Other));   }
};

struct FVector2Fix32
{
	FFix32 X;
	FFix32 Y;

public:
	FVector2Fix32()
	{
		X = 0;
		Y = 0;
	}

	FVector2Fix32(const FFix32& InX, const FFix32& InY)
	{
		X = InX;
		Y = InY;
	}

	FVector2Fix32(const FVector2Fix32& InValue) : X(InValue.X), Y(InValue.Y)
	{
 
	}
	
	FVector2Fix32(const FVector2D& InValue) : X(InValue.X), Y(InValue.Y)
	{
		
	}

	FVector2Fix32(const FIntPoint& InValue) : X(InValue.X), Y(InValue.Y)
	{
		
	}

	FVector2Fix32 operator+(const FVector2Fix32& Other) const
	{
		FVector2Fix32 Ret = *this;
		Ret.X += Other.X;
		Ret.Y += Other.Y;
		return Ret;
	}

	FVector2Fix32 operator-(const FVector2Fix32& Other) const
	{
		FVector2Fix32 Ret = *this;
		Ret.X -= Other.X;
		Ret.Y -= Other.Y;
		return Ret;
	}

	FORCEINLINE static FFix32 CrossProduct(const FVector2Fix32& A, const FVector2Fix32& B)
	{
		return A.X * B.Y - A.Y * B.X;
	}
};
